/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.beanutils; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Iterator; /** * <p>Implementation of <code>DynaClass</code> for DynaBeans that wrap the * <code>java.sql.Row</code> objects of a <code>java.sql.ResultSet</code>. * The normal usage pattern is something like:</p> * <pre> * ResultSet rs = ...; * ResultSetDynaClass rsdc = new ResultSetDynaClass(rs); * Iterator rows = rsdc.iterator(); * while (rows.hasNext()) { * DynaBean row = (DynaBean) rows.next(); * ... process this row ... * } * rs.close(); * </pre> * * <p>Each column in the result set will be represented as a DynaBean * property of the corresponding name (optionally forced to lower case * for portability).</p> * * <p><strong>WARNING</strong> - Any {@link DynaBean} instance returned by * this class, or from the <code>Iterator</code> returned by the * <code>iterator()</code> method, is directly linked to the row that the * underlying result set is currently positioned at. This has the following * implications:</p> * <ul> * <li>Once you retrieve a different {@link DynaBean} instance, you should * no longer use any previous instance.</li> * <li>Changing the position of the underlying result set will change the * data that the {@link DynaBean} references.</li> * <li>Once the underlying result set is closed, the {@link DynaBean} * instance may no longer be used.</li> * </ul> * * <p>Any database data that you wish to utilize outside the context of the * current row of an open result set must be copied. For example, you could * use the following code to create standalone copies of the information in * a result set:</p> * <pre> * ArrayList results = new ArrayList(); // To hold copied list * ResultSetDynaClass rsdc = ...; * DynaProperty[] properties = rsdc.getDynaProperties(); * BasicDynaClass bdc = * new BasicDynaClass("foo", BasicDynaBean.class, * rsdc.getDynaProperties()); * Iterator rows = rsdc.iterator(); * while (rows.hasNext()) { * DynaBean oldRow = (DynaBean) rows.next(); * DynaBean newRow = bdc.newInstance(); * PropertyUtils.copyProperties(newRow, oldRow); * results.add(newRow); * } * </pre> * * @author Craig R. McClanahan * @version $Revision: 926685 $ $Date: 2010-03-23 17:59:08 +0000 (Tue, 23 Mar 2010) $ */ public class ResultSetDynaClass extends JDBCDynaClass implements DynaClass { // ----------------------------------------------------------- Constructors /** * <p>Construct a new ResultSetDynaClass for the specified * <code>ResultSet</code>. The property names corresponding * to column names in the result set will be lower cased.</p> * * @param resultSet The result set to be wrapped * * @exception NullPointerException if <code>resultSet</code> * is <code>null</code> * @exception SQLException if the metadata for this result set * cannot be introspected */ public ResultSetDynaClass(ResultSet resultSet) throws SQLException { this(resultSet, true); } /** * <p>Construct a new ResultSetDynaClass for the specified * <code>ResultSet</code>. The property names corresponding * to the column names in the result set will be lower cased or not, * depending on the specified <code>lowerCase</code> value.</p> * * <p><strong>WARNING</strong> - If you specify <code>false</code> * for <code>lowerCase</code>, the returned property names will * exactly match the column names returned by your JDBC driver. * Because different drivers might return column names in different * cases, the property names seen by your application will vary * depending on which JDBC driver you are using.</p> * * @param resultSet The result set to be wrapped * @param lowerCase Should property names be lower cased? * * @exception NullPointerException if <code>resultSet</code> * is <code>null</code> * @exception SQLException if the metadata for this result set * cannot be introspected */ public ResultSetDynaClass(ResultSet resultSet, boolean lowerCase) throws SQLException { this(resultSet, lowerCase, false); } /** * <p>Construct a new ResultSetDynaClass for the specified * <code>ResultSet</code>. The property names corresponding * to the column names in the result set will be lower cased or not, * depending on the specified <code>lowerCase</code> value.</p> * * <p><strong>WARNING</strong> - If you specify <code>false</code> * for <code>lowerCase</code>, the returned property names will * exactly match the column names returned by your JDBC driver. * Because different drivers might return column names in different * cases, the property names seen by your application will vary * depending on which JDBC driver you are using.</p> * * @param resultSet The result set to be wrapped * @param lowerCase Should property names be lower cased? * @param useColumnLabel true if the column label should be used, otherwise false * * @exception NullPointerException if <code>resultSet</code> * is <code>null</code> * @exception SQLException if the metadata for this result set * cannot be introspected * @since 1.8.3 */ public ResultSetDynaClass(ResultSet resultSet, boolean lowerCase, boolean useColumnLabel) throws SQLException { if (resultSet == null) { throw new NullPointerException(); } this.resultSet = resultSet; this.lowerCase = lowerCase; setUseColumnLabel(useColumnLabel); introspect(resultSet); } // ----------------------------------------------------- Instance Variables /** * <p>The <code>ResultSet</code> we are wrapping.</p> */ protected ResultSet resultSet = null; // --------------------------------------------------------- Public Methods /** * <p>Return an <code>Iterator</code> of {@link DynaBean} instances for * each row of the wrapped <code>ResultSet</code>, in "forward" order. * Unless the underlying result set supports scrolling, this method * should be called only once.</p> * @return An <code>Iterator</code> of {@link DynaBean} instances */ public Iterator iterator() { return (new ResultSetIterator(this)); } /** * Get a value from the {@link ResultSet} for the specified * property name. * * @param name The property name * @return The value * @throws SQLException if an error occurs * @since 1.8.0 */ public Object getObjectFromResultSet(String name) throws SQLException { return getObject(getResultSet(), name); } // -------------------------------------------------------- Package Methods /** * <p>Return the result set we are wrapping.</p> */ ResultSet getResultSet() { return (this.resultSet); } // ------------------------------------------------------ Protected Methods /** * <p>Loads the class of the given name which by default uses the class loader used * to load this library. * Dervations of this class could implement alternative class loading policies such as * using custom ClassLoader or using the Threads's context class loader etc. * </p> * @param className The name of the class to load * @return The loaded class * @throws SQLException if the class cannot be loaded */ protected Class loadClass(String className) throws SQLException { try { return getClass().getClassLoader().loadClass(className); } catch (Exception e) { throw new SQLException("Cannot load column class '" + className + "': " + e); } } }